import { MapLength } from "../info/Predefine";
import GameManager from "../manager/GameManager";
import Player from "../player/Player";
const { ccclass, property } = cc._decorator;

const DefMoveSpeed = 200;
export const MoveClamp = [cc.v3(-3170, -3190), cc.v3(3170, 3150)]

/**
 * 场景中所有能移动的元素需要添加此组件
 */
@ccclass
export default class MoveComp extends cc.Component {
    //没有目标时的移动状态 , 按方向移动
    direction: cc.Vec3;
    // state: MoveState;
    //操控者
    player: Player;

    //有目标时自动追踪目标
    target: cc.Vec3;

    //抵达目标时
    arriveCallback: () => void;

    //移动时是否获得视野;
    monitor: boolean;

    moveSpeed: number;

    /**
     * 是否限制在边界内
     */
    clamp: boolean;

    /**
     * 移动时获得多少视野
     */
    viewRadis: number;
    /**
     * 
     * @param player 操控者
     * @param monitor 移动时是否获得视野
     * @param moveSpeed 移动速度
     */
    public init(player: Player, monitor: boolean, moveSpeed: number = DefMoveSpeed): void {
        this.direction = cc.v3(0, 0);
        this.player = player;
        this.monitor = monitor;
        this.moveSpeed = moveSpeed;
        this.clamp = true;
        this.viewRadis = this.player.extraView;
    }

    setTarget(target: cc.Vec3, arriveCallback?: () => void) {
        this.direction = cc.v3(0, 0);
        this.target = target;
        arriveCallback && (this.arriveCallback = arriveCallback);
    }

    setDirection(diretion: cc.Vec3) {
        this.direction = diretion;
    }

    update(dt: number) {
        if (this.target) {
            this.updateFollowTarget(dt);
        } else {
            this.updateStateMove(dt);
        }
    }

    private updateFollowTarget(dt: number) {
        let curPosition = this.node.position;
        let sub = this.target.sub(curPosition);
        let distanse = sub.mag();
        if (distanse > 8) {
            let dir = sub.normalize();
            let speed = this.moveSpeed * dt;
            curPosition.addSelf(dir.mul(speed));
            this.node.position = curPosition;
        } else {
            this.node.position = this.target;
            this.target = null;
            if(this.arriveCallback){
                let temp = this.arriveCallback;
                this.arriveCallback = null;
                temp();
            }
        }

        if (this.monitor && this.player) {
            let rect = this.node.getBoundingBox();
            let leftUp = GameManager.instance.getMapLocation(cc.v3(rect.xMin, rect.yMax));
            let rightDown = GameManager.instance.getMapLocation(cc.v3(rect.xMax, rect.yMin));
            leftUp.locationX = Math.max(0, leftUp.locationX - this.viewRadis);
            leftUp.locationY = Math.max(0, leftUp.locationY - this.viewRadis);
            rightDown.locationX = Math.min(MapLength - 1, rightDown.locationX + this.viewRadis);
            rightDown.locationY = Math.min(MapLength - 1, rightDown.locationY + this.viewRadis);

            for (let i = leftUp.locationX; i <= rightDown.locationX; i++) {
                for (let j = leftUp.locationY; j <= rightDown.locationY; j++) {
                    this.player.getLocationView({ locationX: i, locationY: j })
                }
            }
        }
    }

    private updateStateMove(dt: number) {
        if (this.direction.equals(cc.Vec3.ZERO)) return;
        let speed = this.moveSpeed * dt;
        let position = this.node.position;
        position.addSelf(this.direction.mul(speed));
        this.clamp && position.clampf(MoveClamp[0], MoveClamp[1]);
        this.node.position = position;
        if (this.monitor && this.player) {
            let rect = this.node.getBoundingBox();
            let leftUp = GameManager.instance.getMapLocation(cc.v3(rect.xMin, rect.yMax));
            let rightDown = GameManager.instance.getMapLocation(cc.v3(rect.xMax, rect.yMin));

            leftUp.locationX = Math.max(0, leftUp.locationX - this.viewRadis);
            leftUp.locationY = Math.max(0, leftUp.locationY - this.viewRadis);
            rightDown.locationX = Math.min(MapLength - 1, rightDown.locationX + this.viewRadis);
            rightDown.locationY = Math.min(MapLength - 1, rightDown.locationY + this.viewRadis);
            for (let i = leftUp.locationX; i <= rightDown.locationX; i++) {
                for (let j = leftUp.locationY; j <= rightDown.locationY; j++) {
                    this.player.getLocationView({ locationX: i, locationY: j })
                }
            }
        }
    }

    protected onDisable(): void {
        this.direction = null;
        this.player = null;
        this.target = null;
        this.arriveCallback = null;
    }
}
